package com.hust360.percent.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.drawable.Drawable;
import android.os.Handler;

/**
 * 封装的线程池的类。实现图片的HashMap缓存机制
 * 获取方式为异步获取，请实现PercentThreadPool类中的
 * DoneLoadingCallback接口，并从写回调方法，在回调方法
 * 中执行加载完成后的操作。
 * @author yangyang
 */
public class PercentThreadPool {
	
	/**
	 * xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 缓存图像的HashMap对象 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
	 * 改为Hashtable, 只是换成Hashtable的原因是，Hashtable是线程安全型的，在多线程环境下，可以防止某种意外的发生
	 * 软引用确保在内存不足且Drawable对象没有强引用的时候，可以被释放
	 */
	private Hashtable<String, SoftReference<Drawable>> imgCacheMap = new Hashtable<String, SoftReference<Drawable>>();
	
	/**
	 * 线程池对象,固定使用10个线程来进行图片加载操作
	 */
	private ExecutorService executorService = Executors.newFixedThreadPool(10); 
	
	/**
	 * 线程通信的Handler对象
	 */
	private final Handler handler = new Handler();
	
	/**
	 * 加载图片的方法, 返回值不代表加载图片是否成功，请实现
	 * DoneLoadingCallback 来执行加载完成后的操作
	 * @param imageUrl 下载图片对应的url地址
	 * @param filename 本地SD卡中图片的缓存文件的绝对路径
	 * @param callback 图片加载完成后的回调接口，当获取不到图片时,回调接口方法参数为null
	 */
	public Drawable loadDrawable(final String imageUrl, final String filename, final DoneLoadingCallback callback) {
		
		/*
		 *如果图片在内存中已经有缓存，则从缓存中获取 
		 *这里用的Key是Filename，因为测试的时候，文件是存在本地的。
		 *在搭建后台之后，应该换成图片的url
		 */
		if (imgCacheMap.containsKey(filename)) {
			SoftReference<Drawable> softReference = imgCacheMap.get(filename);
			if (softReference.get() != null) {
				callback.doneLoading(softReference.get());
				return softReference.get();
			}
		}
		
		/*
		 * 如果图片在sd卡中已经有缓存，从sd卡加载
		 */
		File file = new File(filename);
		if (file.isFile()) {
			try {
				Drawable drawable = Drawable.createFromPath(filename);
				if (drawable != null) {
					SoftReference<Drawable> reference = new SoftReference<Drawable>(drawable);
					imgCacheMap.put(filename, reference);
					callback.doneLoading(drawable);
					return drawable;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		/*
		 * sd卡和内存中都没有。则从网络上下载,
		 * 下载操作在子线程中进行
		 */
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				try {
					
					InputStream is = (new URL(imageUrl).openStream());
					final Drawable drawable = Drawable.createFromStream(is, imageUrl);
					if (drawable != null) {
						SoftReference<Drawable> reference =  new SoftReference<Drawable>(drawable);
						imgCacheMap.put(filename, reference);
					}
					handler.post(new Runnable() {
						@Override
						public void run() {
							callback.doneLoading(drawable);
						}
					});
					if (drawable != null) {
						// 如果下载成功，将下载到的图片缓存到本地sd卡
						FileOutputStream os = new FileOutputStream(filename);
						byte[] buff = new byte[512];
						is.reset();
						while (is != null && is.read(buff) != -1) {
							os.write(buff);
						}
						os.close();
					}
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
		
		return null;
	}
	
	
	/**
	 * 图片加载完成后的回调函数的接口，具体请看回调函数的说明
	 * @author yangyang
	 */
	public interface DoneLoadingCallback {
		/**
		 * 图片加载完成后的回调函数，参数即为下载到的图片或者从内存缓存中取到的图片。
		 * 如果下载图片失败，且sd卡中没有该图片。则参数drawable为null
		 * @param drawable
		 */
		public void doneLoading(Drawable drawable);
	}
	
}
